﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace ConsoleDBase
{
    partial class Menu
    {
        //***** GLOBALS *****
        FileInfo[] datasource; //stores the file informations from datasource folder
        DBase activedbase = null;

        //***** METHODS *****
        //opening screen
        public void Run()
        {
            int s;

            do
            {
                Details();

                List<string> start = new List<string>(new string[] { "Új adatbázis", "Megnyitás", "Kilépés" });
                s = SelectOption(start, true, 10, 9);

                switch (s)
                {
                    case 0: CreateNewDb(); break; //option 0 - creating new database
                    case 1: OpenDb(); break; // option 1 - open exsisting database from hdd
                    case 2: return; //exit
                }

                if (activedbase != null) DatabaseOperations();
            }
            while (true);
        }

        //print tables on screen from active database, and make an option to add new table
        void DatabaseOperations()
        {
            List<string> RelatedTables;
            int s;

            do
            {
                Details();
                
                RelatedTables = SearchTables(activedbase.Name);
                RelatedTables.Add("+ Új tábla hozzáadása");
                RelatedTables.Add("Adatbázis bezárása");

                Console.SetCursorPosition(9, 10);
                Console.ForegroundColor = ConsoleColor.Gray;

                if (RelatedTables.Count == 2)
                {
                    Console.Write("Az adatbázisban jelenleg nincsenek táblák."); // no tables
                }
                else
                {
                    Console.Write("Az adatbázisban az alábbi táblák vannak:");
                }

                Console.ForegroundColor = ConsoleColor.DarkGray;

                s = SelectOption(RelatedTables, true, 10, 12);

                if (s == RelatedTables.Count - 2) // add new table to active database
                {
                    AddNewTable();
                }
                else if(s < RelatedTables.Count - 2) // table selected
                {
                    activedbase.ActivateTable(RelatedTables[s]);
                    TableOperations();
                }
            } while (s != RelatedTables.Count - 1);

            activedbase = null;
        }

        //opens an existing database from datasource folder
        void OpenDb()
        {
            string currentdbase = null;

            currentdbase = SelectDatabase();

            if (currentdbase != null)
            {
                activedbase = new DBase(currentdbase);
            }
            else
            {
                activedbase = null;
            }
        }

        //creates new database by name
        void CreateNewDb()
        {
            string newdbname;

            do
            {
                Details();

                newdbname = StringInput("Add meg az új adatbázis nevét:", 10, 6);
                if (!LegalIdentifier(newdbname)) 
                { 
                    ReportError(10, 9, "Helytelen azonosító."); 
                    continue; 
                }

                RefreshDatasource();

                if (DatabaseExists(newdbname))
                {
                    ReportError(10, 9, "A megadatt néven már létezik adatbázis.");
                    continue;
                }
            } while (DatabaseExists(newdbname) || !LegalIdentifier(newdbname));

            activedbase = new DBase(newdbname);
        }

        //add an empty table to active database
        void AddNewTable()
        {
            string newtablename;

            do
            {
                Details();

                newtablename = StringInput("Add meg az új tábla nevét:", 10, 8); // name of new table
                if(!LegalIdentifier(newtablename)) 
                { 
                    ReportError(10,11,"Helytelen azonosító."); 
                    continue; 
                }

                RefreshDatasource();

                if (TableExistsInDbase(newtablename))
                {
                    ReportError(10, 11, "A megadott néven már létezik tábla az adatbázisban");
                    continue;
                }
            } while (TableExistsInDbase(newtablename) || !LegalIdentifier(newtablename));

            activedbase.AddEmptyTable(newtablename);
        }

        //lists table operations
        //DEFINITIONS are is TableOperationDefinitions.cs
        void TableOperations()
        {
            List<string> options = new List<string>
                (new string[] { "Tábla megjelenítése", "Oszlop felvétele", "Oszlop törlése", "Sor hozzáadása", "Szűrés",
                    "Kiürítés", "Törlés", "Vissza"});

            int s;

            do
            {
                Details();

                s = SelectOption(options, true, 10, 9);

                switch (s)
                {
                    case 0: PrintTable(); break;
                    case 1: AddNewField(); break;
                    case 2: DeleteField(); break;
                    case 3: AddRecord(); break;
                    case 4: Filtering(); break;
                    case 5: ClearTableContent(); break;
                    case 6: DeleteTable(); break;
                    case 7: break;
                }

                if (activedbase.activetable != null)
                    activedbase.SaveActiveTable();

            } while (s != 7 && activedbase.activetable != null);

            activedbase.DeactivateTable();
        }

        //finds the tables related to active database
        List<string> SearchTables(string dbname)
        {
            SortedSet<string> tableset = new SortedSet<string>();
            RefreshDatasource();

            foreach (FileInfo fi in datasource)
            {
                string[] file = fi.Name.Split(new char[] { '.' });
                if (file[0] == dbname) tableset.Add(file[1]);
            }

            List<string> tablelist = tableset.ToList<string>();
            return tablelist;
        }

        //reads in the file infos from datasource folder
        void RefreshDatasource()
        {
            DirectoryInfo dir = new DirectoryInfo("./datasource");
            datasource = dir.GetFiles();
        }

        //tests whether a database already exists in the datasource
        bool DatabaseExists(string dbname)
        {
            int i = 0;
            RefreshDatasource();

            foreach (FileInfo fi in datasource)
            {
                string[] file = fi.Name.Split(new char[] { '.' });
                if (file[0] == dbname)
                {
                    break;
                }
                else
                {
                    ++i;
                }
            }

            return (i != datasource.Length);
        }

        //tests whether a specific table already exists in the database
        bool TableExistsInDbase(string tablename)
        {
            int i = 0;
            RefreshDatasource();

            foreach (FileInfo fi in datasource)
            {
                string[] file = fi.Name.Split(new char[] { '.' });
                if (file[1] == tablename)
                {
                    break;
                }
                else
                {
                    ++i;
                }
            }

            return (i != datasource.Length);
        }

        //makes a SelectOption list of databases
        string SelectDatabase()
        {
            Console.Clear();
            Details();

            SortedSet<string> dbaseset = new SortedSet<string>();
            RefreshDatasource();

            foreach (FileInfo fi in datasource)
            {
                string[] file = fi.Name.Split(new char[] { '.' });
                dbaseset.Add(file[0]);
            }

            List<string> dbaselist = dbaseset.ToList<string>();
            dbaselist.Add("Vissza");

            Console.SetCursorPosition(9, 9);
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.Write("Az alábbi adatbázisok állnak rendelkezésre:");
            Console.ForegroundColor = ConsoleColor.DarkGray;

            int s = SelectOption(dbaselist, true, 10, 11);

            if (s == dbaselist.Count - 1) return null;
            return dbaselist[s];
        }

        //makes a Selectoption list of tables in active darabase
        string SelectTable(string dbase)
        {
            /*SortedSet<string> tableset = new SortedSet<string>();

            foreach (FileInfo fi in datasource)
            {
                string[] file = fi.Name.Split(new char[] { '.' });
                if (file[0] == dbase) tableset.Add(file[1]);
            }*/

            List<string> tablelist = /*tableset.ToList<string>();*/ SearchTables(dbase);
            tablelist.Add("Vissza");

            int s = SelectOption(tablelist, true);

            if (s == tablelist.Count - 1) return null;
            return tablelist[s];
        }

        //Clear and write details on screen - application name, developer, school details
        //PLUS: write database and table name, if they are open
        void Details()
        {
            Console.Clear();
            Console.ForegroundColor = ConsoleColor.White;
           
            //header
            Console.SetCursorPosition(0, 0);
            Console.WriteLine("ConsoleDBase adatbázis kezelő felület");
            Console.WriteLine("Készítette: Hornyák Dávid");
            Console.WriteLine("HODTAAI.ELTE / L6QMGG");

            //footer
            Console.SetCursorPosition(0, Console.WindowHeight - 2);
            Console.WriteLine("2012/13/1");
            Console.Write("ELTE Informatikai Kar");

            //active database name
            if (activedbase != null)
            {
                Console.SetCursorPosition(7, 6);
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write("Adatbázis megnyitva: ");
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write(activedbase.Name);
            }

            //active table name
            if (activedbase != null && activedbase.activetable != null)
            {
                Console.SetCursorPosition(7, 7);
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write("Aktív tábla: ");
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write(activedbase.activetable.Name);
            }

            //separator lines
            for (int i = 0; i < Console.WindowWidth; ++i)
            {
                Console.SetCursorPosition(i, 3);
                Console.Write("_");

                Console.SetCursorPosition(i, Console.WindowHeight - 3);
                Console.Write("_");
            }

            Console.ForegroundColor = ConsoleColor.DarkGray;
        }

        //read in a string input
        private string StringInput(string message, int cursorleft, int cursortop)
        {
            string ret;

            Console.SetCursorPosition(cursorleft, cursortop);
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.Write(message);
            Console.ForegroundColor = ConsoleColor.DarkGray;

            for (int i = cursorleft + 5; i < Console.WindowWidth - 1; ++i)
            {
                Console.SetCursorPosition(cursorleft + 5, cursortop + 1);
                Console.Write(" ");
            }

            Console.SetCursorPosition(cursorleft + 5, cursortop + 1);
            Console.CursorVisible = true;
            ret = Console.ReadLine();

            return ret;
        }

        //menu selection controlled with arrow keys
        private int SelectOption(List<string> options, bool lastdiffers = false, int cursorleft = 10, int cursortop = 6)
        {
            //initial Console position
            int initleft = cursorleft;
            int inittop = cursortop;

            Console.SetCursorPosition(initleft, inittop);
            Console.CursorVisible = false;

            if (options.Count == 0) Console.WriteLine("Nincs választható elem.");

            //first option
            Console.ForegroundColor = ConsoleColor.DarkGray;
            Console.BackgroundColor = ConsoleColor.Gray;

            Console.Write(options[0]);

            Console.BackgroundColor = ConsoleColor.Black;

            //rest options
            for (int i = 1; i < options.Count; ++i)
            {
                if (options.Count > 1 && i == options.Count - 1 && lastdiffers)
                {
                    Console.SetCursorPosition(initleft, inittop + i + 1);
                }
                else
                {
                    Console.SetCursorPosition(initleft, inittop + i);
                }

                Console.Write(options[i]);
            }

            //selecting option
            int opt = 0;
            ConsoleKeyInfo cki = new ConsoleKeyInfo();

            while (true)
            {
                cki = Console.ReadKey(true);

                //UpArrow pressed
                if (cki.Key == ConsoleKey.UpArrow && opt > 0)
                {
                    if (options.Count > 1 && opt == options.Count - 1 && lastdiffers)
                    {
                        Console.SetCursorPosition(initleft, inittop + opt + 1);
                    }
                    else
                    {
                        Console.SetCursorPosition(initleft, inittop + opt);
                    }

                    Console.Write(options[opt]);

                    Console.SetCursorPosition(initleft, inittop + opt - 1);
                    Console.BackgroundColor = ConsoleColor.Gray;
                    Console.Write(options[--opt]);
                    Console.BackgroundColor = ConsoleColor.Black;
                }

                //DownArrow pressed
                if (cki.Key == ConsoleKey.DownArrow && opt < options.Count - 1)
                {
                    Console.SetCursorPosition(initleft, inittop + opt);
                    Console.Write(options[opt]);

                    if (options.Count > 1 && opt == options.Count - 2 && lastdiffers)
                    {
                        Console.SetCursorPosition(initleft, inittop + opt + 2);
                    }
                    else
                    {
                        Console.SetCursorPosition(initleft, inittop + opt + 1);
                    }
                    
                    Console.BackgroundColor = ConsoleColor.Gray;
                    Console.Write(options[++opt]);
                    Console.BackgroundColor = ConsoleColor.Black;
                }

                //Enter pressed
                if (cki.Key == ConsoleKey.Enter)
                {
                    break;
                }
            }

            return opt;
        }

        //tests whether an identifier legal
        bool LegalIdentifier(string str)
        {
            if (string.IsNullOrEmpty(str)) return false;



            return true;
        }
    }
}
